﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization;
using Framework;

namespace SchemaMonitor.json
{
    [DataContract]
    public class CNodeBasic
    {
        //Members
        [DataMember(Order =1)] public int        TypeId { get; set; }
        [DataMember(Order =2)] public CFieldList Fields { get; set; }

        [NonSerialized]        private readonly CField _parent;

        //Constructor
        public CNodeBasic(Dictionary<string, object> dict, CField parent, CTag  t, CUser c) : this(dict, parent, t.Parent, c) { }
        public CNodeBasic(Dictionary<string, object> dict, CField parent, CType t, CUser c) : this(parent, t) 
        {
            this.Fields = new CFieldList(dict, this, c);
        }
        public CNodeBasic(byte[] bin, CField parent, CType t) : this(parent, t)
        {
            if (null == bin || 0 == bin.Length)
                this.Fields = new CFieldList();
            else
                this.Fields = CSerialise.Proto.Deserialise_<CFieldList>(bin);
            this.Fields.Parent = this;
        }
        protected CNodeBasic(CField parent, CType t)
        {
            _parent = parent;
            this.TypeId = t.TypeId;
        }
        private CNodeBasic() { }

        //Properties
        public CMetadata Metadata {  get { return Type.Metadata; } }
        public bool HasMeta { get { return Type.HasMeta; } }
        public string Path
        {
            get
            {
                if (null == _parent)    //Manual
                    return string.Concat("[", Type.TypeName, "]");
                return _parent.Path;
            }
        }
        public CType Type
        {
            get
            {
                return CType.Cache.GetById(TypeId);
            }
        }
        public virtual string Name
        {
            get
            {
				return this.Fields.NameOrId;
			}
		}




		//Helpers
		public CField Set(string key, object value, CUser u)
		{
			if (null == value)
			{
				if (!Fields.Has(key))
					return null;
				var ff = Fields[key];
				Fields.Remove(ff);
				return null;
			}
				
			var f = CField.Factory(key, value, this, u);
			if (Fields.Has(key))
			{
				f = Fields[key];
				f.Value = value;
			}
			else
				this.Fields.Add(f);
			return f;
		}

        public long? GetLong(string key)
        {
            var f = Fields[key];
            if (null == f) return null;
            return f.AsLong;
        }
        public string GetString(string key)
        {
            var f = Fields[key];
            if (null == f) return null;
            return f.AsString;
        }
        public bool? GetBool(string key)
        {
            var f = Fields[key];
            if (null == f) return null;
            return f.AsBool;
        }
        public CNodeBasic GetComposite(string key)
        {
            var f = Fields[key];
            if (null == f) return null;
            return f.AsComposite;
        }


        public Guid Hash()
        {
            return Hash(Fields.Serialise());
        }
        private Guid Hash(byte[] bin)
        {
            return CBinary.Sha128_(bin);
        }
    }
}
